package com.linran.utils.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class MediaInfoUtil {
    final static String MEDIAINFO_CMD = "mediainfo";
    //音频文件
    public static final Pattern AUDIO_BIT_DEPTH_PATTERN = Pattern.compile("Bit depth\\s+: (.*?) bits");
    public static final Pattern SAMPLE_RATE_PATTERN = Pattern.compile("Sampling rate\\s+: (.*?) kHz");
    public static final Pattern CHANNELS_PATTERN = Pattern.compile("Channel\\(s\\)\\s+: (.*?) channel(s)??");
    //视频文件(音频流)
    public static final Pattern BIT_RATE_PATTERN = Pattern.compile("Bit rate\\s+: (\\d*?) kb/s");

    public static List<String> audioParseCommands(String fileUrl) {
        List<String> commands = new ArrayList<>();
        commands.add(MEDIAINFO_CMD);
        commands.add("--Inform='Audio;%BitDepth%;%Track%;%SamplingRate%'");
        commands.add(fileUrl);
        return commands;
    }

    public static List<String> videoParseCommands(String fileUrl) {
        List<String> commands = new ArrayList<>();
        commands.add(MEDIAINFO_CMD);
        commands.add("--Inform='Video;%Track%;%SamplingRate%;%BitRate%'");
        commands.add(fileUrl);
        return commands;
    }

    private static String execCommand(List<String> commands, boolean ignoreErrorExit, String commandDesc) {
        String commandStr = String.join(" ", commands);
        Process process = null;
        ProcessBuilder builder = new ProcessBuilder(commands);
        builder.redirectErrorStream(true);

        int exitValue = -1;
        try {
            long st = System.currentTimeMillis();
            log.info("command: {}, 开始执行...", commandStr);
            process = builder.start();
            int waitFor = process.waitFor();
            exitValue = process.exitValue();
            log.info("命令执行结束, {}, waitFor: {}, exitValue: {}, 耗时: {} ms", commandDesc, waitFor, exitValue, (System.currentTimeMillis() - st));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } catch (IOException e) {
//            throw new BizException("命令执行异常, command: " + commandStr, e);
        }

        String result = null;
        try (InputStream input = process.getInputStream()) {
//            result = IOUtils.toString(input);
            result = input.toString();
        } catch (IOException e) {
//            throw new BizException("获取脚本输出信息异常", e);
        }

        final int success = 0;
        if (!ignoreErrorExit && !Objects.equals(exitValue, success)) {
//            log.info("命令执行非正常退出, 执行信息: {}", result);
//            throw new BizException("命令执行异常, command: " + commandStr);
        }

        return result;
    }

    public static void parseAudioInfo(String fileUrl) {
        //minio去除参数，否则linux执行命令时报错
        int index = fileUrl.indexOf("?");
        if (index != -1) {
            fileUrl = fileUrl.substring(0, index);
        }
        List<String> strings = audioParseCommands(fileUrl);
        String result = execCommand(strings, false, "解析音频信息");
        Matcher bitDepthMatcher = AUDIO_BIT_DEPTH_PATTERN.matcher(result);
        if (bitDepthMatcher.find()) {
            String bitDepth = bitDepthMatcher.group(1);
//            parseInfo.setBitDepth(Integer.valueOf(bitDepth));
        }
        Matcher sampleRateMatcher = SAMPLE_RATE_PATTERN.matcher(result);
        if (sampleRateMatcher.find()) {
            String sampleRate = sampleRateMatcher.group(1);
//            parseInfo.setSampleRate(sampleRate);
        }
        Matcher channelsMatcher = CHANNELS_PATTERN.matcher(result);
        if (channelsMatcher.find()) {
            String channels = channelsMatcher.group(1);
//            parseInfo.setChannels(Integer.valueOf(channels));
        }
        Matcher bitRateMatcher = BIT_RATE_PATTERN.matcher(result);
        if (bitRateMatcher.find()) {
            Integer bitRate = Optional.ofNullable(bitRateMatcher.group(1)).filter(StringUtils::isNotBlank).map(Integer::parseInt).orElse(null);
//            parseInfo.setBitrate(bitRate);
        }
    }

    public static void parseVideoInfo(String fileUrl) {
        //minio去除参数，否则linux执行命令时报错
        int index = fileUrl.indexOf("?");
        if (index != -1) {
            fileUrl = fileUrl.substring(0, index);
        }
        List<String> strings = videoParseCommands(fileUrl);
        String result = execCommand(strings, false, "解析视频信息");
        if (StringUtils.isNotBlank(result)) {
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(result.getBytes())))) {
                boolean audioInfo = false;
                String line = null;
                while ((line = reader.readLine()) != null) {
                    if (line.startsWith("Audio")) {
                        audioInfo = true;
                    }
                    if (audioInfo) {
                        //声道
                        Matcher videoMatcher = CHANNELS_PATTERN.matcher(line);
                        if (videoMatcher.find()) {
                            Integer channels = Optional.ofNullable(videoMatcher.group(1)).filter(StringUtils::isNotBlank).map(Integer::parseInt).orElse(null);
//                            parseInfo.channels(channels);
                        }
                        //采样率
                        Matcher samplingMatcher = SAMPLE_RATE_PATTERN.matcher(line);
                        if (samplingMatcher.find()) {
//                            parseInfo.sampleRate(samplingMatcher.group(1));
                        }
                        //码率
                        Matcher bitRateMatcher = BIT_RATE_PATTERN.matcher(line);
                        if (bitRateMatcher.find()) {
                            Integer bitRate = Optional.ofNullable(bitRateMatcher.group(1)).filter(StringUtils::isNotBlank).map(Integer::parseInt).orElse(null);
//                            parseInfo.bitrate(bitRate);
                        }
                    }
                }
            } catch (IOException ioe) {
                log.error("[视频解析] 音频流信息获取失败", ioe);
            }
        }
    }

}
